package com.example.graphmovieapp.repository;

import com.example.graphmovieapp.domain.entity.Movie;
import com.example.graphmovieapp.domain.entity.Person;
import com.example.graphmovieapp.dto.MovieCountByYear;
import org.springframework.data.neo4j.repository.Neo4jRepository;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.repository.query.Param;
import org.springframework.data.neo4j.repository.query.Query;
import org.springframework.stereotype.Repository;

import java.util.List;
import java.util.Optional;

/**
 * MovieRepository接口，提供对Movie实体的数据访问操作
 * 
 * @author GraphMovieApp
 * @version 1.0
 */
@Repository
public interface MovieRepository extends Neo4jRepository<Movie, Long> {

    /**
     * 按标题查找电影
     * 
     * @param title 电影标题
     * @return 匹配的电影，如果不存在则返回Optional.empty()
     */
    Optional<Movie> findByTitle(String title);

    /**
     * 按发行年份查找电影
     * 
     * @param released 发行年份
     * @return 匹配的电影列表
     */
    List<Movie> findByReleased(Integer released);

    /**
     * 按标题模糊查询电影
     * 
     * @param title 标题关键字
     * @return 包含关键字的电影列表
     */
    List<Movie> findByTitleContaining(String title);

    /**
     * 按标题模糊查询电影（支持分页）
     *
     * @param title 标题关键字
     * @param pageable 分页参数
     * @return 分页的电影列表
     */
    @Query(value = "MATCH (m:Movie) WHERE m.title CONTAINS $title RETURN m ORDER BY m.title SKIP $skip LIMIT $limit",
           countQuery = "MATCH (m:Movie) WHERE m.title CONTAINS $title RETURN count(m)")
    Page<Movie> findByTitleContaining(@Param("title") String title, Pageable pageable);

    /**
     * 按发行年份范围查找电影
     * 
     * @param start 起始年份
     * @param end 结束年份
     * @return 在指定年份范围内的电影列表
     */
    List<Movie> findByReleasedBetween(Integer start, Integer end);

    /**
     * 按发行年份范围查找电影（支持分页）
     *
     * @param start 起始年份
     * @param end 结束年份
     * @param pageable 分页参数
     * @return 分页的电影列表
     */
    @Query(value = "MATCH (m:Movie) WHERE $start <= m.released <= $end RETURN m ORDER BY m.released SKIP $skip LIMIT $limit",
           countQuery = "MATCH (m:Movie) WHERE $start <= m.released <= $end RETURN count(m)")
    Page<Movie> findByReleasedBetween(@Param("start") Integer start, @Param("end") Integer end, Pageable pageable);

    /**
     * 查找指定演员参演的电影数量
     * 
     * @param name 演员姓名
     * @return 该演员参演的电影数量
     */
    @Query("MATCH (p:Person {name: $name})-[:ACTED_IN]->(m:Movie) RETURN count(m)")
    Long countMoviesActedByPerson(@Param("name") String name);

    /**
     * 查找指定导演执导的电影数量
     * 
     * @param name 导演姓名
     * @return 该导演执导的电影数量
     */
    @Query("MATCH (p:Person {name: $name})-[:DIRECTED]->(m:Movie) RETURN count(m)")
    Long countMoviesDirectedByPerson(@Param("name") String name);

    /**
     * 查找同时担任演员和导演的电影
     * 
     * @param name 人物姓名
     * @return 该人物既参演又执导的电影列表
     */
    @Query("MATCH (p:Person {name: $name})-[:ACTED_IN]->(m:Movie) WHERE (p)-[:DIRECTED]->(m) RETURN m")
    List<Movie> findMoviesActedAndDirectedByPerson(@Param("name") String name);

    /**
     * 查找同时担任演员和导演的电影（支持分页）
     *
     * @param name 人物姓名
     * @param pageable 分页参数
     * @return 分页的电影列表
     */
    @Query(value = "MATCH (p:Person {name: $name})-[:ACTED_IN]->(m:Movie) WHERE (p)-[:DIRECTED]->(m) RETURN m ORDER BY m.title SKIP $skip LIMIT $limit",
           countQuery = "MATCH (p:Person {name: $name})-[:ACTED_IN]->(m:Movie) WHERE (p)-[:DIRECTED]->(m) RETURN count(m)")
    Page<Movie> findMoviesActedAndDirectedByPerson(@Param("name") String name, Pageable pageable);

    /**
     * 查找合作演员（参演同一电影的不同演员）
     * 
     * @param name 演员姓名
     * @return 与该演员合作过的其他演员列表
     */
    @Query("MATCH (p1:Person {name: $name})-[:ACTED_IN]->(m:Movie)<-[:ACTED_IN]-(p2:Person) WHERE p1 <> p2 RETURN DISTINCT p2")
    List<Person> findCoActors(@Param("name") String name);

    /**
     * 查找合作演员（参演同一电影的不同演员，支持分页）
     *
     * @param name 演员姓名
     * @param pageable 分页参数
     * @return 分页的合作演员列表
     */
    @Query(value = "MATCH (p1:Person {name: $name})-[:ACTED_IN]->(m:Movie)<-[:ACTED_IN]-(p2:Person) WHERE p1 <> p2 RETURN DISTINCT p2 ORDER BY p2.name SKIP $skip LIMIT $limit",
           countQuery = "MATCH (p1:Person {name: $name})-[:ACTED_IN]->(m:Movie)<-[:ACTED_IN]-(p2:Person) WHERE p1 <> p2 RETURN count(DISTINCT p2)")
    Page<Person> findCoActors(@Param("name") String name, Pageable pageable);

    }